using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Xml.Serialization;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;


public class HotUpdateView : MonoBehaviour
{
    public string[] stateStr = {
        "检查资源版本","检查最新资源","检查本地资源","下载资源中","解压资源中"
    };

    private Action<bool> successAction;
    private string versionPath = "";

    private Text label_tip;
    private Text label_progress;
    private Image img_progress_mask;
    private Button btn_Fix;

    // Start is called before the first frame update
    void Awake()
    {
        versionPath = Utils.GetPersistentDataPath() + "/" + Const.VERSION_FILE_NAME;
        label_tip = this.transform.Find("label_tip").GetComponent<Text>();
        label_progress = this.transform.Find("label_progress").GetComponent<Text>();
        img_progress_mask = this.transform.Find("img_progress_bg/img_progress_mask").GetComponent<Image>();
        btn_Fix = this.transform.Find("btn_Fix").GetComponent<Button>();
        
        if (!Directory.Exists(Utils.GetLocalResLoadPath() + "/lua"))
        {
            Directory.CreateDirectory(Utils.GetLocalResLoadPath() + "/lua");
        }
    }

    // Update is called once per frame
    void Start()
    {
        btn_Fix.onClick.AddListener(() => {
            if (Directory.Exists(Application.persistentDataPath))
            {
                //Player.log文件无法删除会报错 注:打包时可以不要log
                //Directory.Delete(Application.persistentDataPath, true);
                Application.Quit();
            }
        });
        this.HandlerHotUpdate();
    }

    void Update()
    {

    }

    //从本地ab包中解压所有lua代码
    public void LoadAllLuaAsset(Action<bool> p)
    {

        if (Utils.GetIsLocal())
        {
            p?.Invoke(true);
            return;
        }

        this.label_tip.text = stateStr[4];
        var localPath = Utils.GetLocalResLoadPath() +"/";
        FileInfo[] files = new DirectoryInfo(localPath).GetFiles("*.lua");

        

        var index = 0f;
        foreach (var file in files)
        {
            index++;
            SetProgress(index/files.Length);
            var ab = AssetBundle.LoadFromFile(file.FullName);
            var directoryName = file.Name.Replace("_", "/");
            directoryName = directoryName.Replace(".lua", "");
            var finalDireName = localPath + directoryName + "/";
            if(Utils.FindInString(file.Name, "lua_main"))
            {
                finalDireName = localPath + "lua/";
            }
            if (!Directory.Exists(finalDireName))
            {
                Directory.CreateDirectory(finalDireName);
            }
            foreach (var luaFile in ab.LoadAllAssets<TextAsset>())
            {
                var fileName = luaFile.name.Replace(".bytes", ".lua") + ".lua";
                //如果已经存在该文件且文件内容一致
                if (!(File.Exists(finalDireName + fileName) && Utils.GetMD5String(luaFile.bytes) == Utils.GetMD5String(finalDireName + fileName)))
                {
                    //重新从AB包内加载lua
                    File.WriteAllBytes(finalDireName + fileName, luaFile.bytes);
                }
            }
            //把LUA包卸载了不驻在内存了
            ab.Unload(true);
        }
        p?.Invoke(true);
    }

    private void HandlerHotUpdate()
    {
        if (Utils.GetIsLocal())
        {
            this.successAction(true);
            return;
        }
        StartCoroutine(GetVersion());
    }

    private IEnumerator GetVersion()
    {
        this.label_tip.text = stateStr[0];
        var url = Const.RES_IP + Const.RES_PATH + Const.VERSION_FILE_NAME;
        Debug.Log("url:" + url);
        UnityWebRequest webRequest = UnityWebRequest.Get(url);
        webRequest.timeout = 30;//设置超时，若webRequest.SendWebRequest()连接超时会返回，且isNetworkError为true

        yield return webRequest.SendWebRequest();

        bool isError = webRequest.result == UnityWebRequest.Result.ConnectionError || webRequest.result == UnityWebRequest.Result.ProtocolError;
        //if (webRequest.isNetworkError)
        if (isError)
        {
            Debug.Log("Download Error:" + webRequest.error);
        }
        else
        {
            //本地已经有版本清单文件了 , 就删掉了
            if (File.Exists(versionPath))
            {
                File.Delete(versionPath);
            }
            //玩家首次进入，就要开始拉全部资源了
            FileStream newVersionFile = new FileStream(versionPath, FileMode.Create);
            var bytes = webRequest.downloadHandler.data;
            newVersionFile.Write(bytes, 0, bytes.Length);
            newVersionFile.Flush();
            newVersionFile.Close();

            var res = this.CheckNeedDownLoadRes();
            if(res.Count == 0)
            {
                //不用下载资源
                this.successAction(true);
            }
            else
            {
                //需要下载资源
                this.DownLoadAsset(res);
            }
        }
    }

    public void DownLoadAsset(List<string> res)
    {
        this.label_tip.text = stateStr[3];
        SetProgress(0);
        var index = 0;
        foreach (var resName in res)
        {
            Debug.Log("本次更新这些文件 --->>> " + resName);
            NetManager.Instance.AddRequest(Const.RES_IP + Const.RES_PATH + resName, (bytes) => {
                index++;
                SetProgress((float)index / res.Count);
                //将byte[]转为文件
                File.WriteAllBytes(Utils.GetLocalResLoadPath() + "/" + resName, bytes);
                if(index == res.Count)
                {
                    this.successAction(true);
                }
                Thread.Sleep(50);
            });
        }
    }

    public void SetResCheckCallBack(Action<bool> p)
    {
        this.successAction = p;
    }

    /// <summary>
    /// 拿到需要下载的资源列表
    /// </summary>
    /// <returns></returns>
    private List<string> CheckNeedDownLoadRes()
    {
        //加载全部资源
        TextReader filestream = new StreamReader(versionPath);
        var xmlSerializer = new XmlSerializer(typeof(PackageVersion));
        PackageVersion packageVersion = xmlSerializer.Deserialize(filestream) as PackageVersion;

        GameData.gameVersion = packageVersion.version;

        //远程最新的清单文件的数据  [资源名] = md5
        Dictionary<string, string> versionManifestDic = new Dictionary<string, string>();
        //本地当前资源的数据   [资源名] = "";
        Dictionary<string, string> localResDic = new Dictionary<string, string>();
        //需要更新的新资源
        List<string> needUpdateRes = new List<string>();

        //检查清单文件
        var totalVersionNum = packageVersion.resList.Count;
        var index = 0;
        this.label_tip.text = stateStr[1];
        foreach (var resvo in packageVersion.resList)
        {
            SetProgress(index / totalVersionNum);
            versionManifestDic[resvo.resName] = resvo.md5Str;
            index++;
        }

        //拿到本地的资源
        var path = Utils.GetLocalResLoadPath();
        var dicInfo = new DirectoryInfo(path);
        FileInfo[] files = dicInfo.GetFiles();
        index = 0;
        totalVersionNum = files.Length;
        this.label_tip.text = stateStr[2];
        foreach (var file in files)
        {
            SetProgress(index / totalVersionNum);
            localResDic[file.Name] = "";
            if (versionManifestDic.ContainsKey(file.Name))
            {
                //存在文件则检查MD5是否一致
                if(Utils.GetMD5String(file.FullName) != versionManifestDic[file.Name])
                {
                    //MD5不一致 需要下载更新资源
                    needUpdateRes.Add(file.Name);
                }
            }
            else
            {
                //废弃资源 需要删除
                file.Delete();
            }
        }

        foreach (var versionRes in versionManifestDic)
        {
            if (!localResDic.ContainsKey(versionRes.Key))
            {
                //不啦ICON的资源
                if (!Utils.FindInString(versionRes.Key, "icon_"))
                {
                    //本地没有这个资源 也去更新
                    needUpdateRes.Add(versionRes.Key);
                }
            }
        }
        return needUpdateRes;
    }

    private void SetProgress(float progress)
    {
        this.label_progress.text = ((progress / 1) * 100).ToString("0.00") + "%";
        this.img_progress_mask.fillAmount = progress / 1;
    }


    public class PackageVersion
    {
        public string version;
        public List<ResVO> resList = new List<ResVO>();
    }

    public class ResVO
    {
        public string resName;
        public string md5Str;
    }
}
